package com.xyy.saas.payment.controller;

import com.alibaba.fastjson.JSONObject;
import com.xyy.saas.payment.adpater.RouteManager;
import com.xyy.saas.payment.adpater.fumin.spring.SpringConfiguration2;
import com.xyy.saas.payment.adpater.fumin.util.VerifyAndDecryptUtil2;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.cores.enums.*;
import com.xyy.saas.payment.cores.vo.CallbackResultVo;
import com.xyy.saas.payment.dao.model.*;
import com.xyy.saas.payment.merchant.core.dto.AccountModifyNoticeDto;
import com.xyy.saas.payment.merchant.core.dto.AccountOpenNoticeDto;
import com.xyy.saas.payment.merchant.core.service.AccountModifyService;
import com.xyy.saas.payment.merchant.core.service.AccountOpenService;
import com.xyy.saas.payment.merchant.core.service.OpenpayService;
import com.xyy.saas.payment.payment.core.service.DealVirtualAccountChangeService;
import com.xyy.saas.payment.service.*;
import com.xyy.saas.payment.util.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.*;

@Slf4j
@RestController
@RequestMapping(value = {"/api/notify"})
public class AccountChangeController {
    @Resource
    private DealVirtualAccountChangeService dealVirtualAccountChangeService;
    @Resource
    private OpenpayService openpayService;
    @Resource
    private ThirdUserInfoService thirdUserInfoService;
    @Resource
    private ApplyOpenAccountStatusService applyOpenAccountStatusService;
    @Resource
    private ApplypayUserInfoService applypayUserInfo;
    @Resource
    private OpenpayInfoService openpayInfoService;
    @Resource
    private CallbackRunner callbackRunner;
    @Resource
    private PayAccountService payAccountService;
    @Resource
    private RouteManager routeManager;
    @Resource
    private AccountModifyService accountModifyService;
    @Resource
    private AccountOpenService accountOpenService;
    @Autowired
    private SpringConfiguration2 springConfiguration2;

    /**
     * 富民虚账动账通知
     */
    @RequestMapping(value = "/fm_ybm/virtual_account_change", method = RequestMethod.POST)
    public String virtualAccountChange(@RequestBody String body) {
        log.info("AccountChangeController#virtualAccountChange（YBM） notify ,body={}", body);
        dealVirtualAccountChangeService.deal(body);
        return Constants.FBANK_CALLBACK_SUCCESS;
    }

    /**
     * 富民虚账动账通知
     */
    @RequestMapping(value = "/fm_heye/virtual_account_change", method = RequestMethod.POST)
    public String virtualAccountChangeHeye(@RequestBody String body) {
        log.info("AccountChangeController#virtualAccountChange（HEYE） notify ,body={}", body);
        dealVirtualAccountChangeService.deal(body);
        return Constants.FBANK_CALLBACK_SUCCESS;
    }

    /**
     * 开通平台渠道支付功能通知
     */
    @RequestMapping(value = "/fbank/openPay", method = RequestMethod.POST)
    public String openPayChannel(@RequestBody String body) {
        log.info("AccountChangeController#openPayChannel notify ,body={}", body);
        // 解析参数
        List<Object> openPayList = new ArrayList<>();

        try {
            openPayList = (List<Object>) JSONUtils.parse2Map(body, String.class, Object.class).get("body");
        }
        catch(Exception ex) {
            log.error(ex.getMessage() + ", body=" + body ,ex);
            return Constants.FBANK_CALLBACK_FAIL;
        }

        // 是否全部成功
        boolean isFullSuccess = true;

        for(Object openPayStr : openPayList) {
            try {
                // 更新状态
                Map<String, Object> stringStringMap = (Map<String, Object>) openPayStr;
                String fictiAccountNumber = String.valueOf(stringStringMap.get("fictiAccountNumber"));
                String powerId= String.valueOf(stringStringMap.get("piId"));
                // 是否进行微信开户意愿申请
                boolean isOpenAccountApplyment = true;

                ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByThirdUserId(fictiAccountNumber);
                String accountId = thirdUserInfo.getUserId();

                // check 支付功能是否都同步了,没同步过来的针对性的同步一次
                if(!checkAndSyncOpenPayStatus(accountId)) {
                    // 校验不成功
                    log.error("AccountChangeController#openPayChannel openpayService.checkAndSyncOpenPayStatus error. stringStringMap:{},", JSONUtils.toJSON(stringStringMap));
                    return Constants.FBANK_CALLBACK_FAIL;
                }

                List<OpenpayInfo> openpayInfos = openpayService.queryOpenInfoByAccount(accountId, thirdUserInfo.getId());

                for(OpenpayInfo openpayInfo : openpayInfos) {
                    // 遍历查询的所有开通记录修改开通状态 开通的忽略跳过
                    if(Objects.equals(openpayInfo.getPowerId(), powerId) && !openpayInfo.getStatus().equals(OpenPayStatusEnum.SUCCESS_PAY_CHANNEL.getStatus())) {
                        boolean isSuccess = openpayService.updateStatusByPowerId(OpenPayStatusEnum.SUCCESS_PAY_CHANNEL, openpayInfo.getAccountId(), openpayInfo.getThirdUserInfoId(), openpayInfo.getPowerId());

                        if(!isSuccess) {
                            log.error("AccountChangeController#openPayChannel openpayService.updateStatusByPowerId fail. openPayStr:{}, openpayInfo:{}", openPayStr, JSONUtils.toJSON(openpayInfo));
                            isOpenAccountApplyment = false;
                        }
                    }
                    else {
                        // 公众号、小程序 需要验证是否都配置了，若有没有配置的则不发送微信申请
                        if(FBankPowerIdEnum.WX_OFFICIAL.getPowerId().equals(openpayInfo.getPowerId())
                                || FBankPowerIdEnum.WX_MINI.getPowerId().equals(openpayInfo.getPowerId())) {
                            if(!OpenPayStatusEnum.SUCCESS_PAY_CHANNEL.getStatus().equals(openpayInfo.getStatus())) {
                                isOpenAccountApplyment = false;
                            }
                        }
                    }
                }

                log.info("AccountChangeController#openPayChannel accountId:{} isOpenAccountApplyment:{}", accountId, isOpenAccountApplyment);

                if(isOpenAccountApplyment) {
                    // 判断是否短信通知
                    PayAccount payAccount = payAccountService.getPayAccountByAccountId(accountId);
                    ApplypayUserInfo applypayUserInfo = this.applypayUserInfo.queryUserInfoByAccountId(accountId);

                    if(OpenPayStatusEnum.OPENING.getStatus().equals(applypayUserInfo.getStatus())) {
                        callbackRunner.callback(payAccount.getBusinessUserId(), CallbackResultVo.TYPE_CREATE_PAY_PASS, 0,0,null,applypayUserInfo.getCallback(), "", "");
                    }

                    // check 微信开户意愿状态
                    ApplyOpenAccountStatus param = new ApplyOpenAccountStatus();
                    param.setThirdUserId(thirdUserInfo.getThirdUserId());
                    param.setAccountId(accountId);
                    List<ApplyOpenAccountStatus> applyOpenAccountList = applyOpenAccountStatusService.selectByParam(param);

                    if(applyOpenAccountList.size() == 1) {
                        ApplyOpenAccountStatus applyOpenAccountStatus = applyOpenAccountList.get(0);

                        if(applyOpenAccountStatus.getAuthorize() == OpenAccountAuthorizeStatusEnum.AUTHORIZE_STATE_AUTHORIZED.getStatus()) {
                            // 回调业务
                            callbackRunner.callback(payAccount.getBusinessUserId(), CallbackResultVo.TYPE_OPEN_ACCOUNT_SUCCESS, 0,0,null, applypayUserInfo.getCallback(), "");
                        }
                    }
                }
            }
            catch(Exception e) {
                log.error("AccountChangeController#openPayChannel update status fail. openPayStr:{}", openPayStr, e);
                isFullSuccess = false;
            }
        }

        return isFullSuccess ? Constants.FBANK_CALLBACK_SUCCESS : Constants.FBANK_CALLBACK_FAIL;
    }

    /**
     * 富民账户修改审核结果通知
     */
    @RequestMapping(value = "/create/account", method = RequestMethod.POST)
    public String createAccount(@RequestBody String body) {
        log.info("AccountChangeController#createAccount notify, body=" + body);

        try {
            String decryptResult = VerifyAndDecryptUtil2.get().verifyAndDecrypt(springConfiguration2, JSONObject.parseObject(body).getJSONObject("data"));
            log.info("AccountChangeController#createAccount notify, decryptResult=" + decryptResult);

            if(Objects.equals(JSONUtils.getValueFromJson(decryptResult, "notifyType"), "OPEN_AUDIT_NOTIFY")) {
                accountOpenService.dealAuditResult(JSONUtils.parse2Object(decryptResult, AccountOpenNoticeDto.class));
            }
            else {
                accountModifyService.dealAuditResult(JSONUtils.parse2Object(decryptResult, AccountModifyNoticeDto.class));
            }
        }
        catch(Exception ex) {
            log.error("AccountChangeController#createAccount notify deal error. param=" + body + ", message=" + ex.getMessage(), ex);
            return Constants.FBANK_CALLBACK_FAIL_V2;
        }

        return Constants.FBANK_CALLBACK_SUCCESS_V2;
    }

    /**
     * 富民账户修改审核结果通知
     */
    @RequestMapping(value = "/modify/account", method = RequestMethod.POST)
    public String modifyAccount(@RequestBody String body) {
        log.info("AccountChangeController#modifyAccount notify, body=" + body);

        try {
            String decryptResult = VerifyAndDecryptUtil2.get().verifyAndDecrypt(springConfiguration2, JSONObject.parseObject(body).getJSONObject("data"));
            log.info("AccountChangeController#modifyAccount notify, decryptResult=" + decryptResult);

            if(Objects.equals(JSONUtils.getValueFromJson(decryptResult, "notifyType"), "OPEN_AUDIT_NOTIFY")) {
                accountOpenService.dealAuditResult(JSONUtils.parse2Object(decryptResult, AccountOpenNoticeDto.class));
            }
            else {
                accountModifyService.dealAuditResult(JSONUtils.parse2Object(decryptResult, AccountModifyNoticeDto.class));
            }
        }
        catch(Exception ex) {
            log.error("AccountChangeController#modifyAccount notify deal error. param=" + body + ", message=" + ex.getMessage(), ex);
            return Constants.FBANK_CALLBACK_FAIL_V2;
        }

        return Constants.FBANK_CALLBACK_SUCCESS_V2;
    }

    /**
     * 绑卡结果异步通知
     */
    @RequestMapping(value = "/bindcard", method = RequestMethod.POST)
    public String bindCard(@RequestBody String body) {
        log.info("AccountChangeController#bindCard notify, body=" + body);

        try {
            String decryptResult = VerifyAndDecryptUtil2.get().verifyAndDecrypt(springConfiguration2, JSONObject.parseObject(body).getJSONObject("data"));
            log.info("AccountChangeController#bindCard notify, decryptResult=" + decryptResult);
        }
        catch(Exception ex) {
            log.error("AccountChangeController#bindCard notify deal error. param=" + body + ", message=" + ex.getMessage(), ex);
            return Constants.FBANK_CALLBACK_FAIL_V2;
        }

        return Constants.FBANK_CALLBACK_SUCCESS_V2;
    }

    private boolean checkAndSyncOpenPayStatus(String accountId) {
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(accountId);
        List<OpenpayInfo> openpayInfos = openpayService.queryOpenInfoByAccount(accountId, thirdUserInfo.getId());
        boolean isExistOpening = false;

        for(OpenpayInfo openpayInfo : openpayInfos) {
            if(openpayInfo.getStatus().equals(OpenPayStatusEnum.OPENING.getStatus())) {
                isExistOpening = true;
                break;
            }
        }

        // 如果存在开通中的支付功能 手动同步
        if(isExistOpening) {
            PayAccount payAccount = payAccountService.getPayAccountByAccountId(accountId);

            try {
                Map<String, Boolean> result = routeManager.queryOpenPay(accountId, payAccount.getBusinessIdType());

                for(String powerId : result.keySet()) {
                    OpenpayInfo record = new OpenpayInfo();
                    record.setStatus(result.get(powerId) ? OpenPayStatusEnum.SUCCESS_FM.getStatus() : OpenPayStatusEnum.FAIL.getStatus());
                    record.setAccountId(accountId);
                    record.setThirdUserInfoId(thirdUserInfo.getId());
                    record.setPowerId(powerId);
                    record.setVersion(OpenPayStatusEnum.OPENING.getStatus());
                    int rows = openpayInfoService.updateStatusByPowerId(record);

                    if(rows < 1) {
                        log.error("QueryOpenAccountJobServiceImpl#queryOpenPayStatus database error. OpenpayInfo:{}", JSONUtils.toJSON(record));
                        return false;
                    }
                }
            }
            catch(Exception e) {
                log.error("QueryOpenAccountJobServiceImpl#queryOpenPayStatus exception. accountId:{}", accountId);
                return false;
            }
        }

        return true;
    }
}
